package com.ymx.darling.type;

import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.sql.Types;
import java.sql.Timestamp;
import java.sql.Time;
import java.sql.Clob;
import java.sql.Blob;
import java.sql.Array;
import java.sql.Date;
import java.time.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * jdbc类型转换器
 */
public class TypeHandlerRegister {
    private static final Map<Class<?>, TypeHandler<?>> typeHandlerMap;
    private static final Map<Integer, Class<?>> jdbcTypeMapper;

    static {
        /*jdbc与java的类型映射关系*/
        jdbcTypeMapper = new HashMap<>();
        jdbcTypeMapper.put(Types.TINYINT,byte.class);
        jdbcTypeMapper.put(Types.INTEGER,int.class);
        jdbcTypeMapper.put(Types.BIGINT,long.class);
        jdbcTypeMapper.put(Types.REAL,float.class);
        jdbcTypeMapper.put(Types.FLOAT,double.class);
        jdbcTypeMapper.put(Types.DOUBLE,double.class);
        jdbcTypeMapper.put(Types.SMALLINT,short.class);
        jdbcTypeMapper.put(Types.DECIMAL,BigDecimal.class);
        jdbcTypeMapper.put(Types.NUMERIC,BigDecimal.class);
        jdbcTypeMapper.put(Types.CHAR,String.class);
        jdbcTypeMapper.put(Types.VARCHAR,String.class);
        jdbcTypeMapper.put(Types.LONGVARCHAR,String.class);
        jdbcTypeMapper.put(Types.BIT,boolean.class);
        jdbcTypeMapper.put(Types.BOOLEAN,boolean.class);
        jdbcTypeMapper.put(Types.BINARY,byte[].class);
        jdbcTypeMapper.put(Types.VARBINARY,byte[].class);
        jdbcTypeMapper.put(Types.LONGVARBINARY,byte[].class);
        jdbcTypeMapper.put(Types.DATE,Date.class);
        jdbcTypeMapper.put(Types.TIME,Time.class);
        jdbcTypeMapper.put(Types.TIMESTAMP,Timestamp.class);
        jdbcTypeMapper.put(Types.CLOB,Clob.class);
        jdbcTypeMapper.put(Types.BLOB,Blob.class);
        jdbcTypeMapper.put(Types.ARRAY,Array.class);

        /*jdbc类型转换器*/
        typeHandlerMap = new HashMap<>();
        typeHandlerMap.put(Object.class, new ObjectHandler());
        typeHandlerMap.put(String.class, new StringHandler());
        typeHandlerMap.put(BigDecimal.class, new BigDecimalHandler());
        typeHandlerMap.put(boolean.class, new BooleanHandler());
        typeHandlerMap.put(byte.class, new ByteHandler());
        typeHandlerMap.put(char.class, new CharacterHandler());
        typeHandlerMap.put(short.class, new ShortHandler());
        typeHandlerMap.put(int.class, new IntegerHandler());
        typeHandlerMap.put(long.class, new LongHandler());
        typeHandlerMap.put(float.class, new FloatHandler());
        typeHandlerMap.put(double.class, new DoubleHandler());
        typeHandlerMap.put(byte[].class, new ByteArrayHandler());
        typeHandlerMap.put(Boolean.class, new BooleanHandler());
        typeHandlerMap.put(Byte.class, new ByteHandler());
        typeHandlerMap.put(Character.class, new CharacterHandler());
        typeHandlerMap.put(Short.class, new ShortHandler());
        typeHandlerMap.put(Integer.class, new IntegerHandler());
        typeHandlerMap.put(Long.class, new LongHandler());
        typeHandlerMap.put(Float.class, new FloatHandler());
        typeHandlerMap.put(Double.class, new DoubleHandler());
        typeHandlerMap.put(Byte[].class, new ByteObjectArrayHandler());
        typeHandlerMap.put(Date.class, new DateHandler());
        typeHandlerMap.put(java.util.Date.class, new UtilDateHandler());
        typeHandlerMap.put(Time.class, new TimeHandler());
        typeHandlerMap.put(Timestamp.class, new TimestampHandler());
        typeHandlerMap.put(Clob.class, new ClobHandler());
        typeHandlerMap.put(Blob.class, new BlobHandler());
        typeHandlerMap.put(Array.class, new ArrayHandler());
        typeHandlerMap.put(Reader.class, new ReaderHandler());
        typeHandlerMap.put(LocalDate.class, new LocalDateHandler());
        typeHandlerMap.put(LocalTime.class, new LocalTimeHandler());
        typeHandlerMap.put(LocalDateTime.class, new LocalDateTimeHandler());
        typeHandlerMap.put(InputStream.class, new InputStreamHandler());
        typeHandlerMap.put(Month.class, new MonthHandler());
        typeHandlerMap.put(Year.class, new YearHandler());
        typeHandlerMap.put(YearMonth.class, new YearMonthHandler());
    }


    /**
     * 判断是否存在指定的类型转换器
     * @param type 查找的转换器的类型
     * @return true 存在 false 不存在
     */
    public static boolean typeIsExists(Class<?> type) {
        return Objects.nonNull(getTypeHandler(type));
    }


    /**
     * 返回一个与指定类型相匹配的转换器
     *
     * @param type 指定转换器的类型
     * @return TypeHandler
     */
    public static TypeHandler<?> getTypeHandler(Class<?> type){
        TypeHandler<?> typeHandler = typeHandlerMap.get(type);
        if (typeHandler != null) {
            return typeHandler;
        } else { //判断type是否为以下几种类型的子类型
            if (InputStream.class.isAssignableFrom(type)) {
                return getTypeHandler(InputStream.class);
            } else if (Array.class.isAssignableFrom(type)) {
                return getTypeHandler(Array.class);
            } else if (Clob.class.isAssignableFrom(type)) {
                return getTypeHandler(Clob.class);
            } else if (Blob.class.isAssignableFrom(type)) {
                return getTypeHandler(Blob.class);
            } else if (Reader.class.isAssignableFrom(type)) {
                return getTypeHandler(Reader.class);
            } else if (Enum.class.isAssignableFrom(type)) {
                return new EnumTypeHandler((Class<Enum<?>>) type);
            } else {
                return null;
            }
        }
    }


    /**
     * 返回jdbc对应的java的Class类型
     * @param type jdbc类型
     * @return java类型的Class
     */
    public static Class<?> getJavaType(int type){
        return jdbcTypeMapper.get(type);
    }
}
